#pragma once

#include "Buffer.hpp"
#include "Socket.hpp"
#include "Any.hpp"
#include "Reactor.hpp"
#include "IdManage.hpp"

using namespace std;
using namespace LogMudule;
using namespace SocketModule;

enum class ConnectionStatus
{
    // 连接关闭状态:此时不能再对连接进行操作
    DISCONNECTED = 0,
    // 连接刚刚创建，但是未初始化完成(回调未注册等)
    CONNECTING,
    // 可以正常工作的状态,连接初始化完成，回调函数等也设置完成
    CONNECTEN,
    // 待关闭状态,连接不能想关闭就马上关闭
    DISCONNECTING // 因为可能连接的发送/接收缓冲区还有数据未处理，如果直接关闭那就会有问题
};

// 只管理IO连接
class Connection : public enable_shared_from_this<Connection>
{
    // 一次_socket->Recv最多接收的字节数（默认64KB）
    static const uint64_t DefaultRecvMaxSize = 64 * 1024;

    // 用户（连接）接收缓冲区最大的容量(默认64MB)
    static uint64_t MaxReadBufferCapacity;

    // 连接建立完成时调用的回调
    typedef function<void(shared_ptr<Connection>)> ConnectionCallback;
    // 业务处理回调
    typedef function<void(shared_ptr<Connection>, Buffer *)> OperationsCallback;
    // 连接关闭时调用的回调
    typedef function<void(shared_ptr<Connection>)> CloseCallback;
    // 连接有任意事件发生时，都会调用的回调
    typedef function<void(shared_ptr<Connection>)> AnyEventCallback;
    // 用户接收缓冲区容量超限时，需要调用的回调，bool*类型的参数表示是否关闭该连接, 如果关闭请设置为true
    typedef function<void(shared_ptr<Connection>, Buffer *, bool *)> BufferCapacityExceededLimitCallback;

    // 组件内的Server模块设置进来的关闭连接的回调
    typedef function<void(shared_ptr<Connection>)> ServerCloseCallback;

private:
    // 指向连接所属的Reactor对象
    Reactor *_belongs_reactor;
    // 连接的唯一标识符，便于连接的查找和管理
    uint64_t _conn_id;
    // 连接对应的超时销毁的定时任务的ID
    uint64_t _timer_id;
    // 连接对应的fd
    int _sockfd;
    // 连接对应的封装的套接字
    SockPtr _socket;
    // 连接状态
    ConnectionStatus _status;

    // 超时销毁时间，即连接多长时间没通信，就释放该连接
    uint32_t _timerout;
    // 是否开启非活跃连接超时释放（默认false）
    bool _enable_inactive_release;

    // 连接的用户级接收缓冲区
    Buffer _read_buf;
    // 连接的用户级发送缓冲区
    Buffer _write_buf;
    // 连接的事件管理
    Channel _channel;
    // 请求协议类的上下文（对象）
    Any _context;

    /////////// 用户注册 /////////////////////////

    // 连接建立完成时调用的回调
    ConnectionCallback _connection_callback;
    // 对Buffer接收缓冲区中的数据处理时，调用的业务处理回调
    OperationsCallback _operations_callback;
    // 连接关闭时调用的回调
    CloseCallback _close_callback;
    // 连接有任意事件发生时，都会调用的回调
    AnyEventCallback _any_event_callback;

    // 用户接收缓冲区容量超限时，需要调用的回调
    BufferCapacityExceededLimitCallback _buffer_capacity_exceeded_limit_callback;

    /////////// 组件内的Server模块注册 ///////////////

    // 组件内的Server模块设置进来的关闭连接的回调
    ServerCloseCallback _server_close_callback;

private:
    // 在所属的Reactor线程里执行的真正释放连接的接口
    void ReleaseInLoop()
    {
        // 如果连接已经是关闭状态了，就说明关闭过了，直接return
        if (_status == ConnectionStatus::DISCONNECTED)
        {
            return;
        }

        // 把连接状态设置为关闭状态
        _status = ConnectionStatus::DISCONNECTED;
        // 如果存在定时销毁任务
        if (_belongs_reactor->HasTimerTask(_timer_id))
        {
            // 就取消定时销毁任务
            _belongs_reactor->CanceledTimerTask(_timer_id);
        }
        // 取消监控
        _channel.Remove();
        // 调用用户设置的关闭连接的回调
        if (_close_callback)
        {
            _close_callback(shared_from_this());
        }
        // 关闭fd
        LOG(LogLevel::DEBUG) << "连接关闭,对应sockfd: " << _sockfd;
        _socket->Close();
        // 调用服务器组件的销毁连接回调
        if (_server_close_callback)
        {
            _server_close_callback(shared_from_this());
        }
        else
        {
            LOG(LogLevel::ERROR) << "TcpSever模块没有设置业务处理回调,无法进行业务处理";
            abort();
        }
    }
    // 真正释放连接的接口
    void Release()
    {
        // 直接放进任务队列，为了防止执行回调的过程中连接被释放，导致程序崩溃
        _belongs_reactor->QueueInLoop(std::bind(&Connection::ReleaseInLoop, this));
    }

    // 连接对应的socketfd读事件触发后调用的回调，会设置给连接对应的socketfd对应的Channel
    void HandleRead()
    {
        LOG(LogLevel::DEBUG) << "sockfd: " << _sockfd << "读事件就绪";
        // 非阻塞循环从TCP内核接收缓冲区中读取数据
        while (true)
        {
            string in;
            int ret = _socket->Recv(in, DefaultRecvMaxSize);
            // 如果读取成功
            if (ret > 0)
            {
                // 写入连接的用户级接收缓冲区
                _read_buf.WriteString(in);

                // 如果用户一次性发送超大型文件/数据，则可能导致用户接收缓冲区频繁扩容
                // 大量消耗资源，可能导致服务器崩溃
                // 所以一旦超过用户设置的 用户接收缓冲区容量上限 就调用用户设置的回调
                if (_read_buf.ReadAbleSize() > MaxReadBufferCapacity)
                {
                    // 调用用户设置的处理该情况的回调
                    if (_buffer_capacity_exceeded_limit_callback)
                    {
                        // 标识是否关闭该连接
                        bool is_close_connection = false;
                        _buffer_capacity_exceeded_limit_callback(shared_from_this(),
                                                                 &_read_buf,
                                                                 &is_close_connection);

                        // 如果连接关闭
                        if (is_close_connection == true)
                        {
                            // 清空用户级接收缓冲区
                            _read_buf.Clear();
                            // 尝试关闭连接
                            ShutdownInLoop();
                            return;
                        }
                    }
                    else
                    {
                        // 如果用户没设置就提醒一下用户
                        LOG(LogLevel::WARNING) << "接收到超大型报文,但用户未设置【用户接收缓冲区】容量上限时，处理的回调";
                    }
                }
            }
            else if (ret == 0) // 如果连接断开
            {
                // 尝试关闭连接
                LOG(LogLevel::DEBUG) << "sockfd: " << _sockfd << "连接断开";
                ShutdownInLoop();
                return;
            }
            else
            {
                // 如果TCP内核接收缓冲区没油数据了
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                // 如果被信号中断
                else if (errno == EINTR)
                {
                    // 尝试重新读取
                    continue;
                }
                else // 连接fd异常
                {
                    LOG(LogLevel::WARNING) << "recv sockfd: " << _sockfd << "异常";
                    // 尝试关闭连接
                    ShutdownInLoop();
                    return;
                }
            }
        }

        // 调用业务处理的回调函数
        if (_operations_callback)
        {
            _operations_callback(shared_from_this(), &_read_buf);
        }
        else
        {
            LOG(LogLevel::ERROR) << "用户没有设置业务处理回调,无法进行业务处理";
            abort;
        }
    }
    // 连接对应的socketfd写事件触发后调用的回调，会设置给连接对应的socketfd对应的Channel
    void HandleWrite()
    {
        // 非阻塞循环向TCP内核接收缓冲区中发送数据
        while (true)
        {
            // 读取连接对应的用户级发送缓冲区中的数据,能读多少就读多少
            string buf;
            _write_buf.ReadAsString(&buf, _write_buf.ReadAbleSize());

            int ret = _socket->Send(buf, buf.size());
            if (ret > 0) // 发送了ret个字节
            {
                // 如果缓冲区满了,但是读取出来的数据没发完,就要把剩余数据写回缓冲区保存
                if (ret < buf.size())
                {
                    LOG(LogLevel::DEBUG) << "用户缓冲区还有数据，但是内核缓冲区满了";
                    // 计算buf剩余字节个数
                    uint64_t remainder = buf.size() - ret;
                    // 因为数据现在还不会被覆盖，所以读指针前移即可
                    _write_buf.MoveReadOffset(-remainder);
                    break;
                }
            }
            else if (ret == 0) // 发送了0个字节
            {
                // 连接的用户级发送缓冲区中没数据了
                break;
            }
            else
            {
                // 如果TCP内核发送缓冲区满了
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                // 如果被信号中断
                else if (errno == EINTR)
                {
                    // 尝试重新读取
                    continue;
                }
                else // 连接fd异常
                {
                    LOG(LogLevel::WARNING) << "write sockfd: " << _sockfd << "异常";
                    // 如果用户级接收还有数据
                    if (_read_buf.ReadAbleSize() > 0)
                    {
                        if (_operations_callback)
                        {
                            _operations_callback(shared_from_this(), &_read_buf);
                        }
                        else
                        {
                            LOG(LogLevel::ERROR) << "用户没有设置业务处理回调,无法进行业务处理";
                            abort();
                        }
                    }
                    // 处理完了就直接关闭连接
                    Release();
                    return;
                }
            }
        }

        // 如果缓冲区中还有数据,就说明内核缓冲区满了
        if (_write_buf.ReadAbleSize() > 0)
        {
            // 启动写事件监控
            if (_channel.WriteAble() == false) // 如果没有启动，才需要启动
                _channel.EnableWrite();
        }
        else // 否则，因为写事件不能常监控
        {
            // 就取消读事件监控
            _channel.DisableWrite();
        }

        // 如果连接为待关闭状态
        if (_status == ConnectionStatus::DISCONNECTING)
        {
            // 如果用户级接收还有数据，就处理一下
            if (_read_buf.ReadAbleSize() > 0)
            {
                if (_operations_callback)
                {
                    _operations_callback(shared_from_this(), &_read_buf);
                }
                else
                {
                    LOG(LogLevel::ERROR) << "用户没有设置业务处理回调,无法进行业务处理";
                    abort();
                }
            }
            // 如果连接的用户级发送缓冲区没有数据了
            if (_write_buf.ReadAbleSize() == 0)
            {
                // 直接关闭连接
                Release();
            }
        }
    }
    // 连接对应的socketfd任意事件触发后调用的回调，会设置给连接对应的socketfd对应的Channel
    void HandleEvent()
    {
        // 调用一下组件使用者设置进来的任意事件触发后调用的回调
        if (_any_event_callback)
            _any_event_callback(shared_from_this());

        // 如果启动了非活跃连接超时销毁，才需要刷新一下连接的活跃度
        if (_enable_inactive_release == true)
            _belongs_reactor->RefreshTimerTask(_timer_id, _timerout);
    }
    //连接对应的socketfd连接断开事件触发后调用的回调，会设置给连接对应的socketfd对应的Channel
    void HandleClose()
    {
        // 尝试关闭连接
        ShutdownInLoop();
    }
    //连接对应的socketfd异常事件触发后调用的回调，会设置给连接对应的socketfd对应的Channel
    void HandleError()
    {
        // 尝试关闭连接
        ShutdownInLoop();
    }

    // 在所属的Reactor线程里执行的写入数据到用户级发送缓冲区
    void SendInLoop(Buffer &data)
    {
        // 连接状态不能是关闭状态,关闭状态的连接什么都干不了了
        if (_status == ConnectionStatus::DISCONNECTED)
        {
            return;
        }
        // 写入数据到用户级发送缓冲区
        _write_buf.WriteBuffer(data);

        // 启动写事件监控
        if (_channel.WriteAble() == false) // 如果没有启动，才需要启动
            _channel.EnableWrite();
    }
    // 在所属的Reactor线程里执行的提供给组件使用者的关闭接口
    void ShutdownInLoop()
    {
        // 修改连接状态为  待关闭状态
        _status = ConnectionStatus::DISCONNECTING;

        // 如果连接监控了读事件
        if (_channel.ReadAble() == true)
        {
            // 就取消连接的读事件监控，不再接收后续数据
            // 因为都打算关闭这个连接了
            _channel.DisableRead();
        }

        // 如果用户级接收还有数据
        if (_read_buf.ReadAbleSize() > 0)
        {
            LOG(LogLevel::DEBUG) << "用户接收缓冲区还有数据";
            if (_operations_callback)
            {
                // 最后处理一次
                _operations_callback(shared_from_this(), &_read_buf);
            }
            else
            {
                LOG(LogLevel::ERROR) << "用户没有设置业务处理回调,无法进行业务处理";
                abort();
            }
        }
        // 如果用户级发送还有数据
        if (_write_buf.ReadAbleSize() > 0)
        {
            LOG(LogLevel::DEBUG) << "用户发送缓冲区还有数据";
            // 启动写事件监控
            if (_channel.WriteAble() == false) // 如果没有启动，才需要启动
                _channel.EnableWrite();
        }
        // 如果没有数据，就关闭连接
        else if (_write_buf.ReadAbleSize() == 0)
        {
            LOG(LogLevel::DEBUG) << "准备关闭连接";
            // 关闭连接
            Release();
        }
    }
    // 在所属的Reactor线程里执行的，根据组件使用者指定的秒（参数sec）启动非活跃连接超时销毁
    void EnableInactiveReleaseInLoop(int sec)
    {
        // 修改状态
        _enable_inactive_release = true;
        // 更新超时时间
        _timerout = sec;

        //如果id为0，则视为未初始化ID
        if(_timer_id==0)
        {
            // 申请定时任务id
            _timer_id = IdManager::GetId();
        }

        // 如果已经存在定时销毁任务
        if (_belongs_reactor->HasTimerTask(_timer_id))
        {
            // 就刷新定时销毁任务
            _belongs_reactor->RefreshTimerTask(_timer_id, _timerout);
        }
        else // 如果不存在定时销毁任务
        {
            // 就添加
            _belongs_reactor->AddTimerTask(_timer_id, _timerout, bind(&Connection::Shutdown, this));
        }
    }
    // 在所属的Reactor线程里执行的，关闭非活跃连接超时销毁
    void CancelInactiveReleaseInLoop()
    {
        // 修改状态
        _enable_inactive_release = false;
        // 清零超时时间
        _timerout = 0;

        // 如果已经存在定时销毁任务
        if (_belongs_reactor->HasTimerTask(_timer_id))
        {
            // 就取消定时销毁任务
            _belongs_reactor->CanceledTimerTask(_timer_id);
        }
    }
    // 在所属的Reactor线程里执行的，连接建立完成之后，需要做的各种设置和初始化
    void EstablelishedInLoop()
    {
        // 给_channel设置回调函数
        _channel.SetReadCallback(std::bind(&Connection::HandleRead, this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite, this));
        _channel.SetErrorCallback(std::bind(&Connection::HandleError, this));
        _channel.SetEventCallback(std::bind(&Connection::HandleEvent, this));
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose, this));
        // 启动读事件监控
        _channel.EnableRead();
        // 设置状态为：连接初始化完成
        _status = ConnectionStatus::CONNECTEN;
        // 调用组件使用者注册的连接建立完成时调用的回调
        if (_connection_callback)
            _connection_callback(shared_from_this());
    }

public:
    Connection(Reactor *belongs_reactor, int sockfd, uint64_t conn_id, uint64_t timer_id, uint32_t timeout)
        : _belongs_reactor(belongs_reactor),
          _conn_id(conn_id),
          _timer_id(timer_id),
          _sockfd(sockfd),
          _socket(make_shared<TcpSocket>(sockfd)),
          _status(ConnectionStatus::CONNECTING),
          _timerout(timeout),
          _enable_inactive_release(false),
          _channel(belongs_reactor, sockfd),
          _connection_callback(nullptr),
          _operations_callback(nullptr),
          _close_callback(nullptr),
          _any_event_callback(nullptr),
          _buffer_capacity_exceeded_limit_callback(nullptr),
          _server_close_callback(nullptr)
    {
        // 把fd设置成非阻塞的
        SocketModule::FdSetNonBlock(sockfd);
    }
    // 发送数据到用户级发送缓冲区
    void Send(const char *data, size_t len)
    {
        // 为了保证在任务队列中延迟执行SendInLoop时，data生命周期不过期
        // 所以定义临时对象保存数据，并且传值SendInLoop是传参
        Buffer buf;
        buf.Write(data, len);
        _belongs_reactor->RunInLoop(std::bind(&Connection::SendInLoop, this, move(buf)));
    }
    void Send(const string &data)
    {
        // 为了保证在任务队列中延迟执行SendInLoop时，data生命周期不过期
        // 所以定义临时对象保存数据，并且传值SendInLoop是传参
        Buffer buf;

        buf.WriteString(data);
        _belongs_reactor->RunInLoop(std::bind(&Connection::SendInLoop, this, move(buf)));
    }

    // 提供给组件使用者的关闭接口
    void Shutdown()
    {
        _belongs_reactor->RunInLoop(std::bind(&Connection::ShutdownInLoop, this));
    }

    // 根据组件使用者指定的秒（参数sec）启动非活跃连接超时销毁
    void EnableInactiveRelease(int sec)
    {
        _belongs_reactor->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, sec));
    }
    // 关闭非活跃连接超时销毁
    void CancelInactiveRelease()
    {
        _belongs_reactor->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop, this));
    }

    // 连接建立完成之后，需要做的各种设置和初始化
    void Establelished()
    {
        _belongs_reactor->RunInLoop(std::bind(&Connection::EstablelishedInLoop, this));
    }

    // 判断连接是否处于可以正常工作的CONNECTEN状态
    bool IsConnected()
    {
        return _status == ConnectionStatus::CONNECTEN;
    }

    // 设置请求协议类的上下文（对象）
    void SetContext(const Any &context)
    {
        _context = context;
    }
    // 右值版本的设置
    void SetContext(const Any &&context)
    {
        _context = move(context);
    }

    // 获取协议类的上下文（对象）
    Any *GetContext()
    {
        return &_context;
    }

    // 设置连接建立完成时调用的回调
    void SetConnectionCallback(const ConnectionCallback &conn)
    {
        _connection_callback = conn;
    }
    // 设置业务处理回调
    void SetOperationsCallback(const OperationsCallback &oper)
    {
        _operations_callback = oper;
    }
    // 设置连接关闭时调用的回调
    void SetCloseCallback(const CloseCallback &clo)
    {
        _close_callback = clo;
    }
    // 设置连接有任意事件发生时，都会调用的回调
    void SetAnyEventCallback(const AnyEventCallback &an)
    {
        _any_event_callback = an;
    }
    // 设置用户接收缓冲区容量超限时，需要调用的回调(bool*类型的参数表示是否需要继续对该连接进行读取)
    void SetBufferCapacityExceededLimitCallback(const BufferCapacityExceededLimitCallback &exceeded_limit_callback)
    {
        _buffer_capacity_exceeded_limit_callback = exceeded_limit_callback;
    }

    // 设置组件内的Server模块设置进来的关闭连接的回调
    void SetServerCloseCallback(const ServerCloseCallback &ser)
    {
        _server_close_callback = ser;
    }

    // 获取连接对应的ID
    uint64_t ConnectionID()
    {
        return _conn_id;
    }
    // 获取连接对应的定时销毁任务的ID
    uint64_t TimerID()
    {
        return _timer_id;
    }
    int Fd()
    {
        return _sockfd;
    }
    // 设置用户（连接）接收缓冲区最大的容量
    static void SetMaxReadBufferCapacity(uint64_t capacity)
    {
        MaxReadBufferCapacity = capacity;
    }
    ~Connection()
    {
    }
};

// 用户（连接）接收缓冲区最大的容量(默认64MB)
uint64_t Connection::MaxReadBufferCapacity = 64 * 1024 * 1024;